#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include "settings.h"
#include "nls.h"

void
make_dir_with_parents(const gchar* path)
{
    GList *dirs = NULL;
    gchar *dir_name = g_strdup (path);
    while ( !g_file_test (dir_name, G_FILE_TEST_EXISTS) )
    {
        dirs = g_list_prepend (dirs, dir_name);
        dir_name = g_path_get_dirname (dir_name);
    }

    // Now create all of them.
    GList *dir = g_list_first (dirs);
    while ( NULL != dir )
    {
        if ( -1 == g_mkdir ((gchar *) dir->data, 0700) )
        {
            g_warning (_("Can't make directory '%s'\n"), (gchar *) dir->data);
        }
        g_free (dir->data);
        dir = g_list_next (dir);
    }
    g_list_free (dirs);
}

GKeyFile * parse_settings(const gchar * conf_dir)
{
  make_dir_with_parents(conf_dir);
  gchar * path = g_build_filename(conf_dir, "config", NULL);
  GError * error = NULL;

  GKeyFile * keyfile = g_key_file_new();

  if (!g_key_file_load_from_file(keyfile, path, G_KEY_FILE_KEEP_COMMENTS, &error))
    g_message(_("Can't read config file: %s\n%s\n"), path, error->message);
  g_free(path);
  return keyfile;
}

void save_settings(GKeyFile * kf, const gchar * conf_dir)
{
  gsize length = 0;
  gchar * contents = g_key_file_to_data (kf, &length, NULL);
  gchar * path = g_build_filename(conf_dir, "config", NULL);

  FILE * conf_file = g_fopen (path, "w");
  g_free(path);

  if ( NULL != conf_file )
  {
        fwrite (contents, sizeof (gchar), length, conf_file);
        fclose (conf_file);
  }

  g_free (contents);
}

gchar** parse_command_line(gint* argc, gchar*** argv)
{
  gboolean show_version = FALSE;
  gchar ** files = NULL;
  gint fnum;
  GOptionEntry entries[] =
  {
    { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, N_("show version and exit"), NULL },
    { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &files, NULL, N_("[FILE...]")},
    { NULL }
  };
  GOptionContext *context;
  GError *error = NULL;

  context = g_option_context_new(NULL);
  g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
  g_option_group_set_translation_domain(g_option_context_get_main_group(context), GETTEXT_PACKAGE);
  g_option_context_set_help_enabled(context, TRUE);
  g_option_context_set_summary(context, PACKAGE_NAME " - " N_("Bittorrent network client"));
  g_option_context_add_group(context, gtk_get_option_group(TRUE));
  g_option_context_parse(context, argc, argv, &error);
  g_option_context_free(context);

  if(show_version)
  {
    g_print(PACKAGE_NAME " " PACKAGE_VERSION " " PACKAGE_BUGREPORT);
    g_print(_("(built on %s with GTK %d.%d.%d, GLib %d.%d.%d)"),
        __DATE__, GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
        GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
    g_print("\n");
    exit(0);
  }

  return files;
}

gint socket_connect(const gchar *path)
{
  gint sock;
  struct sockaddr_un addr;

  sock = socket(PF_UNIX, SOCK_STREAM, 0);
  if (sock < 0)
  {
    perror("socket_connect(): socket");
    return -1;
  }

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

  if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
  {
    //perror("socket_connect(): connect");
    return -1;
  }

  return sock;
}

gint socket_open(const gchar * path)
{
  gint sock;
  struct sockaddr_un addr;
  gint val;

  sock = socket(PF_UNIX, SOCK_STREAM, 0);

  if (sock < 0)
  {
    perror("socket_open(): socket");
    return -1;
  }

  val = 1;
  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
  {
    perror("socket_open(): setsockopt");
    close(sock);
    return -1;
  }

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  {
    perror("socket_open(): bind");
    close(sock);
    return -1;
  }

  if (listen(sock, 1) < 0)
  {
    perror("socket_open(): listen");
    close(sock);
    return -1;
  }

  return sock;
}

void socket_send(gint sock, gchar ** files)
{
  gint fnum = g_strv_length(files);
  gint wnum;
  gint x;
  gchar * home;
  gchar * buf;

  home = g_get_current_dir();

  for ( x = 0; x < fnum; ++x )
  {
    if(g_path_is_absolute(files[x]))
      buf = g_strdup_printf("%s\n", files[x]);
    else
      buf = g_build_path(home, files[x], NULL);

    wnum = write(sock, files[x], strlen(buf));
    g_free(buf);
    if (wnum < 0)
    {
      perror("socket_send() : write");
    }
  }

  g_free(home);
}

gchar * socket_receive(gint fd)
{
  struct sockaddr addr;
  gint addr_len = sizeof(addr);
  gchar buf[4096];
  gint len;

  gint sock = accept(fd, (struct sockaddr *) &addr, &addr_len);
  if (sock < 0)  return;

  len = read(sock, &buf, 4096);
  if(len > 0)
  return g_strndup(buf, len);
}

gint init_socket(gchar * path, gchar ** files)
{
  gint sock = socket_connect(path);
  if(sock < 0)
  {
    unlink(path);
    return socket_open(path);
  }

  if (files) socket_send(sock, files);

  close(sock);
  g_free(path);
  return -1;
}

void close_socket(gint sock, gchar * path)
{
  close(sock);

  if (path)
  {
    unlink(path);
    g_free(path);
  }
}
